﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization;
using NUnit.Framework;

namespace Simhopp.Common
{
    /// <summary>
    /// The User class provides the credentials of a user (password not included).
    /// </summary>
    [Serializable]
    public class User : ISerializable, IDatabaseObject
    {
        #region FIELD REGION
        private int id;
        private String userName;
        private Credentials credentials = new Credentials();
        private AccountTypes accountType;
        private int credentialsId;
        private int competitionId;
        #endregion
        #region CONSTRUCTOR REGION
        /// <summary>
        /// Default constructor.
        /// </summary>
        public User()
        {
            id = -1;
            userName = "";
            accountType = AccountTypes.NoAccess;
            credentials.Name = "";
            credentials.Gender = Genders.Male;
            credentials.Age = 0;
            credentials.Nationality = "";
            credentials.SocialSecurityNumber = "";
            accountType = AccountTypes.NoAccess;
            HasSubmittedScore = false;
        }
        #endregion
        #region PROPERTY REGION
        /// <summary>
        /// Property Id gets or sets id.
        /// </summary>
        public int Id
        {
            get { return id; }
            set { id = value; }
        }
        /// <summary>
        /// Property CompetitionId gets or sets the credentialsId.
        /// </summary>
        public int CompetitionId
        {
            get { return competitionId; }
            set { competitionId = value; }
        }
        /// <summary>
        /// Property Username gets or sets the username field.
        /// </summary>
        public String UserName
        {
            get { return userName; }
            set { userName = value; }
        }
        /// <summary>
        /// Property Name gets or sets the name field.
        /// </summary>
        public String Name
        {
            get { return credentials.Name; }
            set { credentials.Name = value; }
        }
        /// <summary>
        /// Property Gender gets or sets the gender field.
        /// </summary>
        public Genders Gender
        {
            get { return credentials.Gender;}
            set { credentials.Gender = value; }
        }
        /// <summary>
        /// Property Age gets or sets the age field.
        /// </summary>
        public int Age
        {
            get { return credentials.Age; }
            set { credentials.Age = value; }
        }
        /// <summary>
        /// Property Nationality gets or sets the nationality field.
        /// </summary>
        public String Nationality
        {
            get { return credentials.Nationality; }
            set { credentials.Nationality = value; }
        }
        /// <summary>
        /// Property SocialSecurityNumber gets or sets the social security number.
        /// </summary>
        public String SocialSecurityNumber
        {
            get { return credentials.SocialSecurityNumber; }
            set { credentials.SocialSecurityNumber = value; }
        }
        /// <summary>
        /// Property Credentials gets or sets the credentials.
        /// </summary>
        public Credentials Credentials
        {
            get { return credentials; }
            set { credentials = value; }
        }
        /// <summary>
        /// Property CredentialsId gets or sets the credentialsId.
        /// </summary>
        public int CredentialsId
        {
            get { return credentialsId; }
            set { credentialsId = value; }
        }
        /// <summary>
        /// Property CredentialsId gets or sets the credentialsId.
        /// </summary>
        public AccountTypes AccountType
        {
            get { return accountType; }
            set { accountType = value; }
        }
        /// <summary>
        /// Gets or sets a bool value indicating whether the user has submitted a score for the current dive.
        /// </summary>
        public bool HasSubmittedScore { get; set; }
        #endregion
        #region METHOD REGION
        /// <summary>
        /// Checks if two instances of the object are identical
        /// </summary>
        /// <param name="obj">The object to compare with</param>
        /// <returns>True/False</returns>
        public override bool Equals(object obj)
        {
            return ((obj as User) == null) ? false : (obj as User).Id == this.Id;
        }
        /// <summary>
        /// Used in addition to Equals method
        /// </summary>
        /// <returns>A unique id</returns>
        public override int GetHashCode()
        {
            return id;
        }
        #endregion
        #region DATABASE REGION
        /// <summary>
        /// Creates a dictionary from the object where member field names are mapped to their corresponding values
        /// </summary>
        /// <returns>A dictionary</returns>
        public Dictionary<String, Object> GetDictionary()
        {
            try
            {
                var dictionary = new Dictionary<String, Object>
                {
                    {"Id", Id.ToString(CultureInfo.InvariantCulture)},
                    {"Username", UserName},
                    {"CredentialsId", this.CredentialsId.ToString(CultureInfo.InvariantCulture)},
                    {"AccountType", ((int) accountType).ToString(CultureInfo.InvariantCulture)},
                    {"CompetitionId", competitionId.ToString(CultureInfo.InvariantCulture)}
                };
                return dictionary;
            }
            catch (Exception e)
            {
                MyLogger.Error("Failed to create dictionary from User object - " + e.Message);
                return null;
            }
        }

        /// <summary>
        /// Creates an User object from a passed dictionary
        /// </summary>
        /// <param name="data">A dictionary where database field names are mapped to their corresponding values</param>
        /// <returns>A User object</returns>
        public static User GetFromDictionary(Dictionary<String, Object> data)
        {
            var user = new User
            {
                Credentials = null
            };
            try
            {
                user.Id = (int) data["Id"];
            }
            catch (Exception e)
            {
                user.Id = -1;
            }
            try
            {
                user.UserName = ((String) data["UserName"]).Trim();
            }
            catch (Exception e)
            {
                user.UserName = "";
            }

            try
            {
                user.CredentialsId = (int) data["CredentialsId"];
            }
            catch (Exception e)
            {
                user.CredentialsId = -1;
            }
            try
            {
                user.CompetitionId = (int) data["CompetitionId"];
            }
            catch (Exception e)
            {
                user.CompetitionId = -1;
            }
            try
            {
                user.accountType = (AccountTypes) data["AccountType"];
            }
            catch (Exception e)
            {
                user.AccountType = AccountTypes.NoAccess;
            }

            return user;
        }

        /// <summary>
        /// Returns the name of the Id field used in the corresponding database-table
        /// </summary>
        /// <returns></returns>
        public String GetIdFieldName()
        {
            return "Id";
        }

        /// <summary>
        /// Returns the name of the databasetable containing this class
        /// </summary>
        /// <returns></returns>
        public String GetTableName()
        {
            return "Users";
        }


        #endregion
        #region SERIALIZE/DESERIALIZE REGION
        /// <summary>
        /// Adds the class specific information used in the serialization of an object.
        /// </summary>
        /// <param name="info">The class specific information.</param>
        /// <param name="context">Describes the source and destination of a given serialized stream.</param>
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Username", userName, typeof(String));
            info.AddValue("Credentials", credentials, typeof(Credentials));
            info.AddValue("accountType", accountType, typeof(AccountTypes));
            info.AddValue("id", Id, typeof(int));
            info.AddValue("CompetitionId", CompetitionId, typeof(int));
        }
        /// <summary>
        /// Constructor used in the deserialization of an object.
        /// </summary>
        /// <param name="info">The class specific information.</param>
        /// <param name="context">Describes the source and destination of a given serialized stream.</param>
        protected User(SerializationInfo info, StreamingContext context)
        {
            id = (int)info.GetValue("id", typeof(int));
            userName = (String)info.GetValue("Username", typeof(String));
            credentials = (Credentials)info.GetValue("Credentials", typeof(Credentials));
            AccountType = (AccountTypes)info.GetValue("accountType", typeof(AccountTypes));
            CompetitionId = (int)info.GetValue("CompetitionId", typeof(int));
        }
        #endregion
    }
}
